home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-08-04 | 53.2 KB | 1,707 lines |
-
- /* Generated by Interface Builder */
-
- #import "defs.h"
- #import "PlotView.h"
- #import "Plot.h"
- #import <appkit/SavePanel.h>
- #import <appkit/color.h>
- #import <appkit/FormCell.h>
- #import <appkit/PrintPanel.h>
- #import <appkit/Pasteboard.h>
-
- /* The following routines are in auxil.m: */
- extern void count_labels(int *, double *, double, double, double);
- extern void autoformat(double, double, double, int *);
- extern void handformat(float, char *, int *);
-
- @implementation PlotView
-
- - (BOOL) acceptsFirstMouse { return YES;} /* grab that mouse down event! */
-
- - provideMainTitleFont { return newMainTitleFont;}
- - provideXTitleFont { return newXTitleFont;}
- - provideYTitleFont { return newYTitleFont;}
- - provideLegendTitleFont { return newLegendTitleFont;}
- - provideLegendFont { return newLegendFont;}
- - provideTicLabelFont { return newTicLabelFont;}
- - (NXPoint) provideLegendBoxOrigin { return legendbox.origin;}
- - (NXPoint) provideXTitleBoxOrigin { return xtitlebox.origin;}
- - (NXPoint) provideYTitleBoxOrigin { return ytitlebox.origin;}
- - (NXPoint) provideMainTitleBoxOrigin { return maintitlebox.origin;}
-
- - provideWindowFrame:(NXRect *)windowframe
- {
- return [[self window] getFrame:windowframe];
- }
-
- /* All these method names that start with "force" would more naturally start
- * with "set", but everything malfunctions then; apparently it's a bad idea
- * to have methods whose names begin with "set". Is it also a bad idea to
- * have methods whose names begin with "init"?
- */
- - forceWindowFrame:(NXRect *)windowframe
- {
- [[self window] placeWindow:windowframe];
- oldbounds = bounds; /* have to do this right here so that the */
- [self display]; /* title boxes are not moved around again */
- return self;
- }
-
- - forceLegendBoxOrigin: (NXPoint)point
- {
- legendbox.origin = point;
- return self;
- }
-
- - forceXTitleBoxOrigin: (NXPoint)point
- {
- xtitlebox.origin = point;
- return self;
- }
-
- - forceYTitleBoxOrigin: (NXPoint)point
- {
- ytitlebox.origin = point;
- return self;
- }
-
- - forceMainTitleBoxOrigin: (NXPoint)point
- {
- maintitlebox.origin = point;
- return self;
- }
-
- - forceMainTitleFont:(char *)fontname :(float)fontsize
- {
- newMainTitleFont =
- [Font newFont:fontname size:fontsize style:0 matrix:NX_IDENTITYMATRIX];
- return self;
- }
-
- - forceXTitleFont:(char *)fontname :(float)fontsize;
- {
- newXTitleFont =
- [Font newFont:fontname size:fontsize style:0 matrix:NX_IDENTITYMATRIX];
- return self;
- }
-
- - forceYTitleFont:(char *)fontname :(float)fontsize;
- {
- newYTitleFont =
- [Font newFont:fontname size:fontsize style:0 matrix:NX_IDENTITYMATRIX];
- return self;
- }
-
- - forceLegendFont:(char *)fontname :(float)fontsize;
- {
- newLegendFont =
- [Font newFont:fontname size:fontsize style:0 matrix:NX_IDENTITYMATRIX];
- return self;
- }
-
- - forceLegendTitleFont:(char *)fontname :(float)fontsize;
- {
- newLegendTitleFont =
- [Font newFont:fontname size:fontsize style:0 matrix:NX_IDENTITYMATRIX];
- return self;
- }
-
- - forceTicLabelFont:(char *)fontname :(float)fontsize;
- {
- newTicLabelFont =
- [Font newFont:fontname size:fontsize style:0 matrix:NX_IDENTITYMATRIX];
- return self;
- }
-
- - initFrame:(const NXRect *)frameRect
- {
- [super initFrame:frameRect];
- legendbox.origin.x = XOFFSET + 50.0; /* get the legendbox initialized here */
- legendbox.origin.y = YOFFSET + 50.0;
- xtitlebox.origin.x = XOFFSET/4.0
- + (bounds.size.width - DEFAULTAXISTITLEWIDTH)/2.0;
- xtitlebox.origin.y = bounds.origin.y + 10.0;
- xtitlebox.size.width = DEFAULTAXISTITLEWIDTH;
- xtitlebox.size.height = DEFAULTFONTSIZE;
- ytitlebox.origin.x = bounds.origin.x + 6.0;
- ytitlebox.origin.y = YOFFSET/4.0
- + (bounds.size.height - DEFAULTAXISTITLEWIDTH)/2.0;
- ytitlebox.size.width = DEFAULTFONTSIZE;
- ytitlebox.size.height = DEFAULTAXISTITLEWIDTH;
- maintitlebox.origin.x = XOFFSET/4.0
- + (bounds.size.width - DEFAULTMAINTITLEWIDTH)/2.0;
- maintitlebox.origin.y = bounds.size.height - 2.0 - 14.0;
- maintitlebox.size.width = DEFAULTMAINTITLEWIDTH;
- maintitlebox.size.height = 14.0;
-
- oldbounds = bounds;
-
- return self;
- }
-
- - (NXCoord *)xdata:(int)n /* we use this in drawing the legend curves */
- {
- xlegend[0] = (legendbox.origin.x + 5.33333)/ppxunit;
- /* We used to have 5.0 instead of 5.33333, but that can give erroneous-looking
- * (albeit correct) results when writing to the screen: the pixels that are
- * turned on when drawing a filled circle, for example, are much different
- * when the circle's center is precisely at a pixel than when the circle's center
- * is not precisely at a pixel. The results are much better when the center
- * of the circle is at a half-pixel point, and so that's what we do.
- */
- xlegend[1] = xlegend[0] + 40.0/ppxunit;
- /* curve fragment in legend is 40 pixels in length */
- if (!drawingLegendLines) xlegend[0] = 0.5*(xlegend[0] + xlegend[1]);
- return xlegend;
- }
-
- - (NXCoord **)ydata:(int)n /* we use this in drawing the legend curves */
- {
- int ncurves = [plotParam nCurvesTotal];
- int j;
- float yloc, yhgt=DEFAULTFONTSIZE;
- const char * curvetitle;
-
- yhgt = [newLegendFont pointSize];
-
- if (yhgt==0) yhgt = DEFAULTFONTSIZE;
-
- yloc = (legendbox.origin.y - 2.0)/ppyunit;
-
- ylegend = (NXCoord **)realloc((void *)ylegend, ncurves*sizeof(NXCoord *));
- for (j = 0; j < ncurves; j++) {
- *(ylegend+j) = (NXCoord *)NULL; /* this is necessary */
- *(ylegend+j) = (NXCoord *)realloc((void *)*(ylegend+j), 2*sizeof(NXCoord));
- /* check for no lines and no symbols */
- if ( ([plotParam providelinestyle:j] == NOLINE) &&
- ([plotParam providesymbolstyle:j] == NOSYMBOL) ) continue;
- /* check for empty curvetitle */
- curvetitle = [legendForm stringValueAt:j];
- if ((drawingLegendLines || drawingLegendSymbols) && curvetitle[0]=='\0')
- continue;
- yloc = yloc + (yhgt+0.33333)/ppyunit;
- /* We used to have just yhgt (instead of yhgt+0.33333); see comments in preceding
- * routine for the reason to change it.
- */
- }
-
- for (j=0; j<ncurves; j++) {
- *(*(ylegend+j)+0) = yloc;
- *(*(ylegend+j)+1) = yloc;
- /* check for no lines and no symbols */
- if( ([plotParam providelinestyle:j] == NOLINE) &&
- ( [plotParam providesymbolstyle:j] == NOSYMBOL) )continue;
- /* check for empty curvetitle */
- curvetitle = [legendForm stringValueAt:j];
- if ((drawingLegendLines || drawingLegendSymbols) && curvetitle[0]=='\0')
- continue;
- yloc -= yhgt/ppyunit;
- }
- return ylegend;
- }
-
- - (BOOL)has_ebars:(int)n
- {
- return NO;
- }
-
- - (int)nPoints:(int)n
- {
- if (drawingLegendLines) return 2;
- else return 1;
- }
-
- - (int)nCurves:(int)n
- {
- return [plotParam nCurvesTotal];
- }
-
- - (int)nFiles
- {
- return 1;
- }
-
- - startPlot
- {
- const char * xtitle = [xTitle stringValueAt:0];
- const char * ytitle = [yTitle stringValueAt:0];
- const char * maintitle = [mainTitle stringValueAt:0];
- float yhgt=DEFAULTFONTSIZE;
- id mainTitleFont,axisTitleFont;
-
- NXSetColor([plotParam provideBackgroundColor]);
- [self clear:self];
- PSsetlinewidth(NXDrawingStatus==NX_DRAWING? 0.0: 0.4);
- NXSetColor([plotParam provideTextColor]);
-
- /* get new font from fontmanager */
- if ([plotParam shouldChangeXTitleFont]) {
- newXTitleFont = [theFontManager convertFont:[theFontManager selFont]];
- }
-
- yhgt = [newXTitleFont pointSize];
-
- if (yhgt==0) {
- axisTitleFont =
- [Font newFont:"Helvetica" size:DEFAULTFONTSIZE
- style:0 matrix:NX_IDENTITYMATRIX];
- yhgt = DEFAULTFONTSIZE;
- }
- else {
- axisTitleFont = [Font newFont:[newXTitleFont name]
- size:[newXTitleFont pointSize]
- style:[newXTitleFont style]
- matrix:NX_IDENTITYMATRIX];
- }
-
- [axisTitleFont set];
-
- xtitlebox.size.width = [axisTitleFont getWidthOf:xtitle];
- xtitlebox.size.height = yhgt;
- if (oldbounds.size.width != bounds.size.width
- || oldbounds.size.height != bounds.size.height) {
- /* Couldn't figure out how to do this with windowDidResize or superviewSizeChanged,
- * so this grubby idea (with the global oldbounds variable) is used instead.
- */
- xtitlebox.origin.x = (xtitlebox.origin.x + 0.5*xtitlebox.size.width)
- *(bounds.size.width/oldbounds.size.width) - 0.5*xtitlebox.size.width;
- xtitlebox.origin.y = (xtitlebox.origin.y + 0.5*xtitlebox.size.height)
- *(bounds.size.height/oldbounds.size.height) - 0.5*xtitlebox.size.height;
- legendbox.origin.x = (legendbox.origin.x + 0.5*legendbox.size.width)
- *(bounds.size.width/oldbounds.size.width) - 0.5*legendbox.size.width;
- legendbox.origin.y = (legendbox.origin.y + 0.5*legendbox.size.height)
- *(bounds.size.height/oldbounds.size.height) - 0.5*legendbox.size.height;
- }
- PSmoveto(xtitlebox.origin.x, xtitlebox.origin.y);
- PSshow((char *)xtitle);
-
- /* get new font from fontmanager */
- if ([plotParam shouldChangeYTitleFont]) {
- newYTitleFont =
- [theFontManager convertFont:[theFontManager selFont]];
- }
- yhgt = [newYTitleFont pointSize];
-
- if (yhgt==0) {
- axisTitleFont =
- [Font newFont:"Helvetica" size:DEFAULTFONTSIZE
- style:0 matrix:NX_IDENTITYMATRIX];
- yhgt = DEFAULTFONTSIZE;
- }
- else {
- axisTitleFont = [Font newFont:[newYTitleFont name]
- size:[newYTitleFont pointSize]
- style:[newYTitleFont style]
- matrix:NX_IDENTITYMATRIX];
- }
-
- [axisTitleFont set];
-
- ytitlebox.size.width = yhgt;
- ytitlebox.size.height = [axisTitleFont getWidthOf:ytitle];
- if (oldbounds.size.width != bounds.size.width
- || oldbounds.size.height != bounds.size.height) {
- ytitlebox.origin.x = (ytitlebox.origin.x + 0.5*ytitlebox.size.height)
- *(bounds.size.width/oldbounds.size.width) - 0.5*ytitlebox.size.height;
- ytitlebox.origin.y = (ytitlebox.origin.y + 0.5*ytitlebox.size.width)
- *(bounds.size.height/oldbounds.size.height) - 0.5*ytitlebox.size.width;
- }
- PSmoveto(ytitlebox.origin.x + yhgt, ytitlebox.origin.y);
- PSgsave();
- PSrotate(90.0);
- PSshow((char *)ytitle);
- PSgrestore();
-
- if ([plotParam shouldChangeMainTitleFont]) {
- newMainTitleFont =
- [theFontManager convertFont:[theFontManager selFont]];
- }
- yhgt = [newMainTitleFont pointSize];
-
- if (yhgt==0) {
- mainTitleFont =
- [Font newFont:"Helvetica" size:14.0 style:0 matrix:NX_IDENTITYMATRIX];
- yhgt = 14.0;
- }
- else {
- mainTitleFont = [Font newFont:[newMainTitleFont name]
- size:[newMainTitleFont pointSize]
- style:[newMainTitleFont style]
- matrix:NX_IDENTITYMATRIX];
- }
-
- [mainTitleFont set];
-
- maintitlebox.size.width = [mainTitleFont getWidthOf:maintitle];
- maintitlebox.size.height = yhgt;
- if (oldbounds.size.width != bounds.size.width
- || oldbounds.size.height != bounds.size.height) {
- maintitlebox.origin.x = (maintitlebox.origin.x + 0.5*maintitlebox.size.width)
- *(bounds.size.width/oldbounds.size.width) - 0.5*maintitlebox.size.width;
- maintitlebox.origin.y = (maintitlebox.origin.y + 0.5*maintitlebox.size.height)
- *(bounds.size.height/oldbounds.size.height) - 0.5*maintitlebox.size.height;
- oldbounds = bounds;
- }
- PSmoveto(maintitlebox.origin.x, maintitlebox.origin.y);
- PSshow((char *)maintitle);
-
- // box around the plot:
- if ([borderBoxOnOff state]) {
- PSsetlinewidth([borderBoxThicknessText floatValue]);
- PSmoveto(0.0, 0.0);
- PSlineto(bounds.size.width, 0.0);
- PSlineto(bounds.size.width, bounds.size.height);
- PSlineto(0.0, bounds.size.height);
- PSlineto(0.0, 0.0);
- PSstroke();
- PSsetlinewidth(NXDrawingStatus==NX_DRAWING? 0.0: 0.4);
- }
- // The preceding doesn't work quite right: for some reason the vertical line
- // on the right hand side of the plot doesn't show up on the display. The
- // line is there if you print or preview the file, however.
- return self;
- }
-
- - setDrawColor:(float) color
- {
- PSsetgray(color);
- return self;
- }
-
- - drawLines:sender :(BOOL)xaxislog :(BOOL)yaxislog
- /*
- * This is coded so that when drawLines is called with plotParam as argument,
- * it draws the data curves; when drawLines is called with self (plotView) as
- * argument, it draws the short line segments in the legend box.
- */
- {
- int i, j, jrun, n;
- NXCoord *x;
- NXCoord **y;
- int npoints, ncurves;
- int curveindex = 0; /* cumulative index */
- int linestyle;
- float thick = [lineThicknessText floatValue];
- float pattern0[] = {}; /* solid */
- float pattern1[] = {4.0, 4.0}; /* dash */
- float pattern2[] = {1.0, 3.0}; /* dot */
- float pattern3[] = {7.0, 3.0, 3.0, 3.0}; /* chain dash */
- float pattern4[] = {7.0, 4.0, 1.0, 4.0}; /* chain dot */
- const char * curvetitle;
-
- for (n=0; n<[sender nFiles]; n++) { /* loop over all active files */
- x = [sender xdata:n];
- y = [sender ydata:n];
- ncurves = [sender nCurves:n];
- npoints = [sender nPoints:n];
- PSnewpath();
- PSsetlinewidth(NXDrawingStatus==NX_DRAWING? thick : MAX(thick, 0.4));
- for (jrun=curveindex; jrun<curveindex+ncurves; jrun++) {
- linestyle = [plotParam providelinestyle:jrun];
- NXSetColor([plotParam provideCurveColor:jrun]);
- switch(linestyle) {
- case SOLID:
- PSsetdash(pattern0, 0, 0.0);
- break;
- case DASH:
- PSsetdash(pattern1, 2, 0.0);
- break;
- case DOT:
- PSsetdash(pattern2, 2, 0.0);
- break;
- case CHAINDASH:
- PSsetdash(pattern3, 4, 0.0);
- break;
- case CHAINDOT:
- PSsetdash(pattern4, 4, 0.0);
- break;
- case NOLINE: /* no lines */
- continue;
- }
- if (linestyle == NOLINE) continue; /* no lines, go to next curve */
- /* If we're drawing the legend and there is no title, don't
- * bother to draw the line:
- */
- curvetitle = [legendForm stringValueAt:jrun];
- if (drawingLegendLines && curvetitle[0]=='\0') continue;
- j = jrun - curveindex; /* for indexing into the y array */
- if (!xaxislog && !yaxislog) {
- PSmoveto(x[0]*ppxunit, *(*(y + j)) * ppyunit );
- for (i=1; i<npoints; i++) {
- if ( (i % 512) == 0 ) {
- PSstroke();
- PSnewpath();
- PSmoveto(x[i-1]*ppxunit, *(*(y+j)+i-1) * ppyunit);
- }
- PSlineto(x[i]*ppxunit, *(*(y+j)+i) * ppyunit);
- }
- PSstroke();
- }
- else if (!xaxislog && yaxislog) {
- PSmoveto(x[0]*ppxunit, (float)log10((double)*(*(y + j))) * ppyunit );
- for (i=1; i<npoints; i++) {
- if ( (i % 512) == 0 ) {
- PSstroke();
- PSnewpath();
- PSmoveto(x[i-1]*ppxunit,
- (float)log10((double)*(*(y+j)+i-1)) * ppyunit);
- }
- PSlineto(x[i]*ppxunit, (float)log10((double)*(*(y+j)+i)) * ppyunit);
- }
- PSstroke();
- }
- else if (xaxislog && !yaxislog) {
- PSmoveto((float)log10((double)x[0])*ppxunit, *(*(y + j)) * ppyunit );
- for (i=1; i<npoints; i++) {
- if ( (i % 512) == 0 ) {
- PSstroke();
- PSnewpath();
- PSmoveto((float)log10((double)x[i-1])*ppxunit,
- *(*(y+j)+i-1) * ppyunit);
- }
- PSlineto((float)log10((double)x[i])*ppxunit, *(*(y+j)+i) * ppyunit);
- }
- PSstroke();
- }
- else if (xaxislog && yaxislog) {
- PSmoveto((float)log10((double)x[0])*ppxunit,
- (float)log10((double)*(*(y + j))) * ppyunit );
- for (i=1; i<npoints; i++) {
- if ( (i % 512) == 0 ) {
- PSstroke();
- PSnewpath();
- PSmoveto((float)log10((double)x[i-1])*ppxunit,
- (float)log10((double)*(*(y+j)+i-1)) * ppyunit);
- }
- PSlineto((float)log10((double)x[i])*ppxunit,
- (float)log10((double)*(*(y+j)+i)) * ppyunit);
- }
- PSstroke();
- }
- }
- curveindex += ncurves;
- }
- PSsetdash(pattern0, 0, 0.0); /* back to solid lines */
- return self;
- }
-
- /*
- * Our first idea for drawing the symbols was: draw each symbol just once
- * in an off-screen window, then composite them in where needed. This worked
- * fine for screen drawing (modulo a little difficulty in compositing to just
- * the right spot), but was a miserable failure when it came to printing: the
- * print machinery scaled the composite bitmap. We finally decided to abandon
- * compositing, in the interest of keeping our screen drawing code the same as
- * our printing code. Should check this again under version 2.0.
- */
- - drawSymbols:sender :(BOOL)xaxislog :(BOOL)yaxislog
- /*
- * This is coded so that when drawSymbols is called with plotParam as argument,
- * it draws the data curves; when drawSymbols is called with self (plotView) as
- * argument, it draws the symbols in the legend box.
- */
- {
- /* Our current code in drawSymbols could perhaps be sped up by using wraps
- * or DPSuserpath(). See if it's too slow as it stands before trying to
- * speed it up.
- */
- int i, j, jrun, n;
- float size = 4.0;
- NXCoord *x;
- NXCoord **y;
- int npoints, ncurves;
- int curveindex = 0;
- int symbolstyle;
- register float xtmp, ytmp;
- const char * curvetitle;
-
- size = [symbolSizeText floatValue];
-
- PSgsave();
- for (n=0; n<[sender nFiles]; n++) { /* loop over all active files */
- x = [sender xdata:n];
- y = [sender ydata:n];
- ncurves = [sender nCurves:n];
- npoints = [sender nPoints:n];
- PSnewpath();
- PSsetlinewidth(NXDrawingStatus==NX_DRAWING? 0.0: 0.4);
- for (jrun=curveindex; jrun<curveindex+ncurves; jrun++) {
- symbolstyle = [plotParam providesymbolstyle:jrun];
- NXSetColor([plotParam provideCurveColor:jrun]);
- /* If we're drawing the legend and there is no title, don't
- * bother to draw the symbol:
- */
- curvetitle = [legendForm stringValueAt:jrun];
- if (drawingLegendSymbols && curvetitle[0]=='\0') continue;
- j = jrun - curveindex; /* for indexing into the y array */
- switch(symbolstyle) {
- case NOSYMBOL:
- continue;
- break;
- case CIRCLE:
- for (i=0; i<npoints; i++) {
- /* circle_at(x[i], *(*(y+j)+i)); */
- xtmp = (xaxislog? (float)log10((double)x[i]) : x[i]);
- ytmp = (yaxislog? (float)log10((double)*(*(y+j)+i)) : *(*(y+j)+i));
- PSarc(xtmp * ppxunit, ytmp * ppyunit, size, 0.0, 360.0);
- PSfill();
- }
- break;
- case XMARK:
- for (i=0; i<npoints; i++) {
- /* x_at(x[i], *(*(y+j)+i)); */
- xtmp = (xaxislog? (float)log10((double)x[i]) : x[i]);
- ytmp = (yaxislog? (float)log10((double)*(*(y+j)+i)) : *(*(y+j)+i));
- PSmoveto(xtmp * ppxunit - size, ytmp * ppyunit - size);
- PSrlineto(2.0*size, 2.0*size);
- PSmoveto(xtmp * ppxunit - size, ytmp * ppyunit + size);
- PSrlineto(2.0*size, -2.0*size);
- PSstroke();
- }
- break;
- case UPTRIANGLE:
- for (i=0; i<npoints; i++) {
- /* uptriangle_at(x[i], *(*(y+j)+i)); */
- xtmp = (xaxislog? (float)log10((double)x[i]) : x[i]);
- ytmp = (yaxislog? (float)log10((double)*(*(y+j)+i)) : *(*(y+j)+i));
- PSmoveto(xtmp * ppxunit - size, ytmp * ppyunit - size/SQRT3);
- PSrlineto(2.0*size, 0.0);
- PSrlineto(-size, size*SQRT3);
- PSclosepath();
- PSfill();
- }
- break;
- case DOWNTRIANGLE:
- for (i=0; i<npoints; i++) {
- /* downtriangle_at(x[i], *(*(y+j)+i)); */
- xtmp = (xaxislog? (float)log10((double)x[i]) : x[i]);
- ytmp = (yaxislog? (float)log10((double)*(*(y+j)+i)) : *(*(y+j)+i));
- PSmoveto(xtmp * ppxunit - size, ytmp * ppyunit + size/SQRT3);
- PSrlineto(2.0*size, 0.0);
- PSrlineto(-size, -size*SQRT3);
- PSclosepath();
- PSfill();
- }
- break;
- case DIAMOND:
- for (i=0; i<npoints; i++) {
- /* diamond_at(x[i], *(*(y+j)+i)); */
- /* 3 pixels horizontal, 4 pixels vertical */
- xtmp = (xaxislog? (float)log10((double)x[i]) : x[i]);
- ytmp = (yaxislog? (float)log10((double)*(*(y+j)+i)) : *(*(y+j)+i));
- PSmoveto(xtmp * ppxunit, ytmp * ppyunit - size);
- PSrlineto(3.0/4.0*size, size);
- PSrlineto(-3.0/4.0*size, size); /* gives a pleasing diamond shape */
- PSrlineto(-3.0/4.0*size, -size);
- PSclosepath();
- PSfill();
- }
- break;
- case SQUARE:
- for (i=0; i<npoints; i++) {
- /* square_at(x[i], *(*(y+j)+i)); */
- xtmp = (xaxislog? (float)log10((double)x[i]) : x[i]);
- ytmp = (yaxislog? (float)log10((double)*(*(y+j)+i)) : *(*(y+j)+i));
- PSrectfill(xtmp * ppxunit - size, ytmp * ppyunit - size,
- 2.0*size, 2.0*size);
- }
- break;
- case PLUS:
- for (i=0; i<npoints; i++) {
- /* plus_at(x[i], *(*(y+j)+i)); */
- xtmp = (xaxislog? (float)log10((double)x[i]) : x[i]);
- ytmp = (yaxislog? (float)log10((double)*(*(y+j)+i)) : *(*(y+j)+i));
- PSmoveto(xtmp * ppxunit, ytmp * ppyunit - size);
- PSrlineto(0.0, 2.0*size);
- PSmoveto(xtmp * ppxunit - size, ytmp * ppyunit);
- PSrlineto(2.0*size, 0.0);
- PSstroke();
- }
- break;
- }
- }
- curveindex += ncurves;
- }
- PSgrestore();
-
- return self;
- }
-
- - drawErrorBars :(BOOL)xaxislog :(BOOL)yaxislog
- {
- int n, j, npoints, ncurves, jrun, i;
- NXCoord *x, *ex = NULL; /* ex and ey initialized to avoid */
- NXCoord **y, **ey = NULL; /* compiler warning */
- int curveindex = 0;
- register float xtmp, ytmp, tmp1, tmp2;
- float width = [errorBarBaseWidth floatValue];
- BOOL exbars, eybars;
-
- PSgsave();
- for (n=0; n<[plotParam nFiles]; n++) { /* loop over all active files */
- exbars = [plotParam has_exbars:n];
- eybars = [plotParam has_eybars:n];
- ncurves = [plotParam nCurves:n];
- if (!exbars && !eybars ) { /* skip if no error bars */
- curveindex += ncurves; /* but have to bump this index, */
- continue; /* to get the colors correct */
- }
- x = [plotParam xdata:n]; /* we have to draw error bars */
- if (exbars) {
- ex = [plotParam exdata:n];
- }
- y = [plotParam ydata:n];
- if (eybars) {
- ey = [plotParam eydata:n];
- }
- npoints = [plotParam nPoints:n];
- PSnewpath();
- PSsetlinewidth(NXDrawingStatus==NX_DRAWING? 0.0: 0.4);
- for (jrun=curveindex; jrun<curveindex+ncurves; jrun++) {
- NXSetColor([plotParam provideCurveColor:jrun]);
- j = jrun - curveindex; /* for indexing into the y and ey arrays */
- /* check if error bars are desired */
- if (exbars && [[errorBarMatrix cellAt :n :0] state] == 1) {
- for (i=0; i<npoints; i++) {
- ytmp = (yaxislog? (float)log10((double)*(*(y+j)+i)) : *(*(y+j)+i));
- if (xaxislog) {
- if (x[i] - ex[i] <= 0.0) { /* avoid log of negative */
- tmp1 = (float)log10( (double) x[i] ); /* what to do? */
- }
- else {
- tmp1 = (float)log10( (double) (x[i] - ex[i]) );
- }
- if (x[i] + ex[i] <= 0.0) { /* again avoid log of negative */
- tmp2 = (float)log10( (double) x[i] );
- }
- else {
- tmp2 = (float)log10( (double) (x[i] + ex[i]) );
- }
- }
- else {
- tmp1 = x[i] - ex[i];
- tmp2 = x[i] + ex[i];
- }
- PSmoveto(tmp1 * ppxunit, ytmp * ppyunit);
- PSrlineto((tmp2-tmp1)*ppxunit, 0.0);
- if (width > 0.0) {
- PSmoveto(tmp1 * ppxunit, ytmp*ppyunit - width/2.0);
- PSrlineto(0.0, width);
- PSmoveto(tmp2 * ppxunit, ytmp*ppyunit - width/2.0);
- PSrlineto(0.0, width);
- }
- PSstroke();
- }
- }
- if (eybars && [[errorBarMatrix cellAt :n :j+1] state] == 1) {
- for (i=0; i<npoints; i++) {
- xtmp = (xaxislog? (float)log10((double)x[i]) : x[i]);
- if (yaxislog) {
- if ((*(*(y+j)+i) - *(*(ey+j)+i)) <= 0.0) { /* avoid log of negative */
- tmp1 = (float)log10( (double) (*(*(y+j)+i)) );
- }
- else {
- tmp1 = (float)log10( (double) (*(*(y+j)+i) - *(*(ey+j)+i)) );
- }
- if ((*(*(y+j)+i) + *(*(ey+j)+i)) <= 0.0) { /* avoid log of negative */
- tmp2 = (float)log10( (double) (*(*(y+j)+i)) );
- }
- else {
- tmp2 = (float)log10( (double) (*(*(y+j)+i) + *(*(ey+j)+i)) );
- }
- }
- else {
- tmp1 = *(*(y+j)+i) - *(*(ey+j)+i);
- tmp2 = *(*(y+j)+i) + *(*(ey+j)+i);
- }
- PSmoveto(xtmp * ppxunit, tmp1 * ppyunit);
- PSrlineto(0.0, (tmp2-tmp1)*ppyunit);
- if (width > 0.0) {
- PSmoveto(xtmp*ppxunit - width/2.0, tmp1 * ppyunit);
- PSrlineto(width, 0.0);
- PSmoveto(xtmp*ppxunit - width/2.0, tmp2 * ppyunit);
- PSrlineto(width, 0.0);
- }
- PSstroke();
- }
- }
- }
- curveindex += ncurves;
- }
- PSgrestore();
-
- return self;
- }
-
-
- - startLegend
- {
- id legendtextfont,legendTitleFont;
- const char * curvetitle;
- const char * legendtitle = [legendTitle stringValueAt:0];
- int j;
- int ncurves = [plotParam nCurvesTotal];
- float maxcurvetitlewid = 0;
- float yhgt = DEFAULTFONTSIZE;
-
- if ([plotParam shouldChangeLegendFont]) {
- newLegendFont = [theFontManager convertFont:[theFontManager selFont]];
- }
-
- yhgt = [newLegendFont pointSize]; /* height of text */
-
- /* get legend text font initialized */
- if (yhgt==0) {
- legendtextfont =
- [Font newFont:"Helvetica" size:DEFAULTFONTSIZE
- style:0 matrix:NX_IDENTITYMATRIX];
- yhgt = DEFAULTFONTSIZE;
- }
- else {
- legendtextfont = [Font newFont:[newLegendFont name]
- size:[newLegendFont pointSize]
- style:[newLegendFont style]
- matrix:NX_IDENTITYMATRIX];
- }
-
- [legendtextfont set];
-
- legendbox.size.height = 10.0;
-
- for (j=0; j<ncurves; j++) {
- /* check for no lines and no symbols */
- if( ([plotParam providelinestyle:j] == NOLINE) &&
- ( [plotParam providesymbolstyle:j] == NOSYMBOL) )continue;
- curvetitle = [legendForm stringValueAt:j];
- /* skip this curve if there is no title: */
- if ([legendtextfont getWidthOf:curvetitle] == 0.0) continue;
- maxcurvetitlewid = MAX(maxcurvetitlewid,
- [legendtextfont getWidthOf:curvetitle]);
- legendbox.size.height += yhgt; /* increment by yhgt for every curve */
- }
-
- /* check on legend title width also */
-
- if ([plotParam shouldChangeLegendTitleFont]) {
- newLegendTitleFont = [theFontManager convertFont:[theFontManager selFont]];
- }
-
- yhgt = [newLegendTitleFont pointSize]; /* height of text */
-
- if (yhgt==0) {
- legendTitleFont =
- [Font newFont:"Helvetica" size:DEFAULTFONTSIZE
- style:0 matrix:NX_IDENTITYMATRIX];
- yhgt = DEFAULTFONTSIZE;
- }
- else {
- legendTitleFont = [Font newFont:[newLegendTitleFont name]
- size:[newLegendTitleFont pointSize]
- style:[newLegendTitleFont style]
- matrix:NX_IDENTITYMATRIX];
- }
-
- [legendTitleFont set];
- maxcurvetitlewid = MAX(maxcurvetitlewid,
- [legendTitleFont getWidthOf:legendtitle]);
-
- legendbox.size.width = 5.0 + 40.0 + 5.0 + maxcurvetitlewid + 5.0;
- /* legendboxwidth = L. margin + 40 + space + curve title + R. margin */
- if([legendTitleFont getWidthOf:legendtitle] != 0)
- legendbox.size.height = legendbox.size.height + 2.0*yhgt - 4.0;
- return self;
- }
-
- - drawLegend:sender
- {
- id legendtextfont,legendTitleFont;
- const char * curvetitle;
- const char * legendtitle = [legendTitle stringValueAt:0];
- int j;
- int ncurves = [plotParam nCurvesTotal];
- float yhgt = DEFAULTFONTSIZE;
-
- if ([plotParam shouldChangeLegendFont]) {
- newLegendFont = [theFontManager convertFont:[theFontManager selFont]];
- }
-
- yhgt = [newLegendFont pointSize];
-
- /* get legend text font initialized */
- if (yhgt==0) {
- legendtextfont =
- [Font newFont:"Helvetica" size:DEFAULTFONTSIZE
- style:0 matrix:NX_IDENTITYMATRIX];
- yhgt = DEFAULTFONTSIZE;
- }
- else {
- legendtextfont = [Font newFont:[newLegendFont name]
- size:[newLegendFont pointSize]
- style:[newLegendFont style]
- matrix:NX_IDENTITYMATRIX];
- }
-
- [legendtextfont set];
-
- drawingLegendLines = YES;
- [self xdata:0];
- [self ydata:0];
-
- NXSetColor([plotParam provideBackgroundColor]);
-
- if ([legendOpaque state] == 0) {
- NXRectFill(&legendbox);
- }
-
- [sender drawLines:sender :NO :NO]; /* legend lines, linear axes always */
-
- NXSetColor([plotParam provideTextColor]);
-
- for (j=0; j<ncurves; j++) {
- /* check for no lines and no symbols */
- if ( ([plotParam providelinestyle:j] == NOLINE) &&
- ([plotParam providesymbolstyle:j] == NOSYMBOL) ) continue;
- curvetitle = [legendForm stringValueAt:j];
- /* skip this curve if there is no title: */
- if ([legendtextfont getWidthOf:curvetitle] == 0.0) continue;
- PSmoveto(xlegend[1]*ppxunit + 5.0,
- *(*(ylegend+j)+0) * ppyunit - 0.33*yhgt);
- PSshow((char *)curvetitle);
- }
-
- if ([plotParam shouldChangeLegendTitleFont]) {
- newLegendTitleFont = [theFontManager convertFont:[theFontManager selFont]];
- }
-
- yhgt = [newLegendTitleFont pointSize]; /* height of text */
- if (yhgt==0) {
- legendTitleFont =
- [Font newFont:"Helvetica" size:DEFAULTFONTSIZE
- style:0 matrix:NX_IDENTITYMATRIX];
- yhgt = DEFAULTFONTSIZE;
- }
- else {
- legendTitleFont = [Font newFont:[newLegendTitleFont name]
- size:[newLegendTitleFont pointSize]
- style:[newLegendTitleFont style]
- matrix:NX_IDENTITYMATRIX];
- }
-
- [legendTitleFont set];
- PSmoveto(xlegend[0]*ppxunit - 5.0 + legendbox.size.width/2.0
- - 0.5*[legendTitleFont getWidthOf:legendtitle],
- *(*(ylegend+0)+0) * ppyunit + yhgt);
- PSshow((char *)legendtitle);
- if([legendBoxOnOff state]) {
- PSsetlinewidth(NXDrawingStatus==NX_DRAWING? 0.0: 0.4);
- PSrectstroke(legendbox.origin.x, legendbox.origin.y,
- legendbox.size.width, legendbox.size.height);
- }
- drawingLegendLines = NO;
- drawingLegendSymbols = YES;
- [sender drawSymbols:sender :NO :NO]; /* legend symbols, linear axes always */
- drawingLegendSymbols = NO;
-
- return self;
- }
-
- - clear:sender
- {
- /*
- * Derek Lisoski (dlisoski@cco.caltech.edu) suggests not drawing the
- * opaque background rectangle when you print or save a file. Then
- * when you read the saved plots into a separate drawing program you
- * can overlay multiple plots or get the plots arbitrarily close to
- * each other. There may be some problems with background colors
- * when importing into various applications (Create or Draw, e.g.)
- */
- if (NXDrawingStatus == NX_DRAWING || [opaqueBackgroundButton state] == 0) {
- NXRectFill(&bounds);
- /* for color; had NXEraseRect, but that always fills with white */
- }
- return self;
- }
-
- /*
- * This routine assumes it is called with xmin != xmax and ymin != ymax.
- * Bad things may happen if this is not the case.
- * The input parameters are assumed to be in pixel coordinates.
- */
- - drawTicMarks:(float)xmin :(float)xmax :(float)ymin :(float)ymax
- {
- float pattern0[] = {}; /* solid */
- float pattern2[] = {1.0, 3.0}; /* dot */
- double xinc_unscaled = [plotParam provideXinc];
- double yinc_unscaled = [plotParam provideYinc];
- double xmin_unscaled = [plotParam provideXmin];
- double ymin_unscaled = [plotParam provideYmin];
- double xmax_unscaled = [plotParam provideXmax];
- double ymax_unscaled = [plotParam provideYmax];
- /* It is useful in some fairly extreme cases to have the increments
- * not in pixel coordinates (otherwise can get "bad" labels).
- */
- char ticlabel[32];
- id ticfont, ticfont1;
- float x, y, ticloc_rat, xticloc, yticloc;
- BOOL drawGrid = [gridOnOff state];
- BOOL xaxislog = [plotParam xaxisLog];
- BOOL yaxislog = [plotParam yaxisLog];
- BOOL drawMinorTics = [minorTicMarksOnOff state];
- int ticLocation; /* 0=axes, 1=2 sides, 2=4 sides */
- float ticmarklen = [ticMarkLengthText floatValue];
- int nmin, ninc, nmax, j, i;
- float ticloc, xwid, yhgt=DEFAULTFONTSIZE, yhgt1;
- double first;
- int nlabels;
- int axformat[3];
-
-
- if (strncmp([ticMarkLocation title], "Axes", 4) == 0)
- ticLocation = 0;
- else if (strncmp([ticMarkLocation title], "Frame (2 sides)", 15) == 0)
- ticLocation = 1;
- else
- ticLocation = 2;
-
- if ([plotParam shouldChangeTicLabelFont]) {
- newTicLabelFont = [theFontManager convertFont:[theFontManager selFont]];
- }
-
- yhgt = [newTicLabelFont pointSize];
- if (yhgt==0) {
- ticfont = [Font newFont:"Helvetica" size:DEFAULTFONTSIZE
- style:0 matrix:NX_IDENTITYMATRIX];
- ticfont1 =
- [Font newFont:"Helvetica" size:10.0 style:0 matrix:NX_IDENTITYMATRIX];
- yhgt = DEFAULTFONTSIZE;
- }
- else {
- ticfont = [Font newFont:[newTicLabelFont name]
- size:[newTicLabelFont pointSize]
- style:[newTicLabelFont style]
- matrix:NX_IDENTITYMATRIX];
-
- yhgt1 = (yhgt >= 10.0? yhgt - 2.0 : 8.0);
- ticfont1 = [Font newFont:[newTicLabelFont name]
- size:yhgt1
- style:[newTicLabelFont style]
- matrix:NX_IDENTITYMATRIX];
- }
-
- /* get tic font initialized */
- [ticfont set];
-
- PSnewpath();
- // PSsetlinewidth(NXDrawingStatus==NX_DRAWING? 0.0: 0.4);
- PSsetlinewidth([ticMarkThicknessText floatValue]);
- if (xaxislog) { /* x-axis is logarithmic */
- nmin = (int)floor((double)(xmin/ppxunit));
- nmax = (int)ceil((double)(xmax/ppxunit));
- ninc = (int)rint(log10(xinc_unscaled));
- if (ninc == 0) ninc = 1; /* avoid infinite loop */
- if ([handFormatXaxis state] == 1) {
- axformat[0] = [xFormatLeft intValue];
- axformat[1] = [xFormatRight intValue];
- axformat[2] = [xFormatExponent intValue];
- }
- for (j=nmin; j<=nmax; j+=ninc) {
- if ( (float)j * ppxunit >= xmin && (float)j * ppxunit <= xmax ) {
- if (drawGrid) {
- PSsetlinewidth([gridThicknessText floatValue]);
- PSmoveto((float)j * ppxunit, ymin);
- if ([gridDotted state])
- PSsetdash(pattern2, 2, 0.0);
- else
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(0.0, ABS(ymax-ymin));
- PSstroke();
- PSsetlinewidth([ticMarkThicknessText floatValue]);
- }
- PSmoveto((float)j * ppxunit, ymin - ticmarklen*6.0); /* big tic mark */
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(0.0, ticmarklen*6.0);
- PSstroke();
- if (ticLocation == 2) { /* tics on right and top */
- PSmoveto((float)j * ppxunit, ymax); /* big tic mark */
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(0.0, ticmarklen*6.0);
- PSstroke();
- }
- if ([handFormatXaxis state] == 0) {
- ticloc_rat = yhgt/DEFAULTFONTSIZE;
- PSmoveto((float)j * ppxunit - ticloc_rat*8.0,
- ymin - MAX(24.0*ticloc_rat,
- 24.0*ticloc_rat*(ticmarklen+10.0)/10.0));
- PSshow("10");
- [ticfont1 set];
- PSmoveto((float)j * ppxunit + ticloc_rat*4.0,
- ymin - MAX(16.0*ticloc_rat,
- 8.0*ticloc_rat*(2.0 + 0.3*ticmarklen)));
- sprintf(ticlabel, "%-5d", j);
- PSshow(ticlabel);
- [ticfont set];
- }
- else {
- x = (float) pow((double)10.0, (double)j);
- handformat(x, ticlabel, axformat);
- xwid = [ticfont getWidthOf:ticlabel];
- PSmoveto((float)j * ppxunit - xwid/2.0,
- ymin - yhgt - MAX(5.0, 5.0*ticmarklen));
- PSshow(ticlabel);
- }
- }
- if (drawMinorTics) {
- for (i=2; i<=9; i++) {
- ticloc = (float)j * ppxunit + ppxunit*(float)log10((double)i);
- if ( ticloc>xmin && ticloc<xmax ) {
- PSmoveto(ticloc, ymin - ticmarklen*3.0); /* small tic mark */
- PSrlineto(0.0, ticmarklen*3.0);
- PSstroke();
- if (ticLocation == 2) { /* tics on right and top */
- PSmoveto(ticloc, ymax); /* small tic mark */
- PSrlineto(0.0, ticmarklen*3.0);
- PSstroke();
- }
- }
- }
- }
- }
- }
- else { /* x-axis is linear */
- yticloc = (ticLocation > 0 ? ymin : 2.0*ticmarklen) ;
- /* If inc is big, skip tic marks entirely */
- if (fabs(xinc_unscaled) < fabs(xmax_unscaled - xmin_unscaled)) {
- count_labels(&nlabels, &first, xmin_unscaled, xinc_unscaled, xmax_unscaled);
- if ([handFormatXaxis state] == 1) {
- axformat[0] = [xFormatLeft intValue];
- axformat[1] = [xFormatRight intValue];
- axformat[2] = [xFormatExponent intValue];
- }
- else {
- autoformat(xmin_unscaled, xinc_unscaled, xmax_unscaled, axformat);
- [xFormatLeft setIntValue:axformat[0]];
- [xFormatRight setIntValue:axformat[1]];
- [xFormatExponent setIntValue:axformat[2]];
- }
- /*
- * next loop starts at -1 because there may be room for minor tic
- * marks to the left of the first major tic mark (after a zoom, e.g.)
- */
- for (i = -1; i < nlabels; i++) {
- /* Special test here for what should be exact 0 (but isn't sometimes
- * due to floating-point arithmetic.
- */
- if (fabs(first/xinc_unscaled + (float)i) < 4.0e-7) { /* ugly */
- x = 0.0;
- }
- else {
- x = (first + (xinc_unscaled)*(float)i) * ppxunit;
- }
- if (x >= xmin) { /* ensure major tic mark won't be off edge */
- if (drawGrid) {
- PSsetlinewidth([gridThicknessText floatValue]);
- PSmoveto(x, ymin);
- if ([gridDotted state])
- PSsetdash(pattern2, 2, 0.0);
- else
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(0.0, ABS(ymax-ymin));
- PSstroke();
- PSsetlinewidth([ticMarkThicknessText floatValue]);
- }
- /* Nothing at 0 if we're putting tic marks on axes: */
- if (ticLocation > 0 || x != 0.0) {
- PSmoveto(x, yticloc - ticmarklen*4.0);
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(0.0, ticmarklen*4.0);
- PSstroke();
- if (ticLocation == 2) { /* tics on right and top */
- PSmoveto(x, ymax);
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(0.0, ticmarklen*4.0);
- PSstroke();
- }
- handformat(x/ppxunit, ticlabel, axformat);
- xwid = [ticfont getWidthOf:ticlabel];
- PSmoveto(x - xwid/2.0, yticloc - yhgt - MAX(5.0, 5.0*ticmarklen));
- PSshow(ticlabel);
- }
- }
- if (drawMinorTics) {
- if (ticLocation > 0) { /* tic marks on frame */
- for (j=1; j<=9; j++) {
- ticloc = x + ((xinc_unscaled/10.0)*(float)j)*ppxunit;
- if (ticloc>xmin && ticloc<xmax) {
- PSmoveto(ticloc, yticloc - ticmarklen*2.0);
- PSrlineto(0.0, ticmarklen*2.0);
- PSstroke();
- if (ticLocation == 2) { /* tics on right and top */
- PSmoveto(ticloc, ymax);
- PSrlineto(0.0, ticmarklen*2.0);
- PSstroke();
- }
- }
- }
- }
- else {
- for (j=1; j<=9; j++) {
- ticloc = x + ((xinc_unscaled/10.0)*(float)j)*ppxunit;
- if (ticloc>xmin && ticloc<xmax) {
- PSmoveto(ticloc, -ticmarklen);
- PSrlineto(0.0, 2.0*ticmarklen);
- PSstroke();
- }
- }
- }
- }
- }
- }
- }
- if (yaxislog) { /* y-axis is logarithmic */
- nmin = (int)floor((double)(ymin/ppyunit));
- nmax = (int)ceil((double)(ymax/ppyunit));
- ninc = (int)rint(log10(yinc_unscaled));
- if (ninc == 0) ninc = 1; /* avoid infinite loop */
- if ([handFormatYaxis state] == 1) {
- axformat[0] = [yFormatLeft intValue];
- axformat[1] = [yFormatRight intValue];
- axformat[2] = [yFormatExponent intValue];
- }
- for (j=nmin; j<=nmax; j+=ninc) {
- if ( (float)j * ppyunit >= ymin && (float)j * ppyunit <= ymax ) {
- if (drawGrid) {
- PSsetlinewidth([gridThicknessText floatValue]);
- PSmoveto(xmin, (float)j * ppyunit);
- if ([gridDotted state])
- PSsetdash(pattern2, 2, 0.0);
- else
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(ABS(xmax-xmin), 0.0);
- PSstroke();
- PSsetlinewidth([ticMarkThicknessText floatValue]);
- }
- PSmoveto(xmin - ticmarklen*6.0, (float)j * ppyunit); /* big tic mark */
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(ticmarklen*6.0, 0.0);
- PSstroke();
- if (ticLocation == 2) { /* tics on right and top */
- PSmoveto(xmax, (float)j * ppyunit); /* big tic mark */
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(ticmarklen*6.0, 0.0);
- PSstroke();
- }
- if ([handFormatYaxis state] == 0) {
- ticloc_rat = yhgt/DEFAULTFONTSIZE;
- PSmoveto(xmin - MAX(40.0*ticloc_rat,
- 40.0*ticloc_rat*(ticmarklen+10.0)/10.0),
- (float)j * ppyunit - ticloc_rat*7.0);
- PSshow("10");
- [ticfont1 set];
- PSmoveto(xmin - MAX(24.0*ticloc_rat,
- 4.0*ticloc_rat*(ticmarklen + 6.0)),
- (float)j * ppyunit - ticloc_rat*1.0);
- sprintf(ticlabel, "%-5d", j);
- PSshow(ticlabel);
- [ticfont set];
- }
- else {
- y = (float) pow((double)10.0, (double)j);
- handformat(y, ticlabel, axformat);
- xwid = [ticfont getWidthOf:ticlabel];
- PSmoveto(xmin - xwid - MAX(10.0, 5.0*ticmarklen),
- (float)j * ppyunit + 2.0 - yhgt/2.0);
- PSshow(ticlabel);
- }
- }
- if (drawMinorTics) {
- for (i=2; i<=9; i++) {
- ticloc = (float)j * ppyunit + ppyunit*(float)log10((double)i);
- if (ticloc>ymin && ticloc<ymax) {
- PSmoveto(xmin - ticmarklen*3.0, ticloc); /* small tic mark */
- PSrlineto(ticmarklen*3.0, 0.0);
- PSstroke();
- if (ticLocation == 2) { /* tics on right and top */
- PSmoveto(xmax, ticloc); /* small tic mark */
- PSrlineto(ticmarklen*3.0, 0.0);
- PSstroke();
- }
- }
- }
- }
- }
- }
- else { /* y-axis is linear */
- xticloc = (ticLocation > 0 ? xmin : 2.0*ticmarklen) ;
- /* If inc is big, skip tic marks entirely */
- if (fabs(yinc_unscaled) < fabs(ymax_unscaled - ymin_unscaled)) {
- count_labels(&nlabels, &first, ymin_unscaled, yinc_unscaled, ymax_unscaled);
- if ([handFormatYaxis state] == 1) {
- axformat[0] = [yFormatLeft intValue];
- axformat[1] = [yFormatRight intValue];
- axformat[2] = [yFormatExponent intValue];
- }
- else {
- autoformat(ymin_unscaled, yinc_unscaled, ymax_unscaled, axformat);
- [yFormatLeft setIntValue:axformat[0]];
- [yFormatRight setIntValue:axformat[1]];
- [yFormatExponent setIntValue:axformat[2]];
- }
- /*
- * next loop starts at -1 because there may be room for minor tic
- * marks to the left of the first major tic mark (after a zoom, e.g.)
- */
- for (i = -1; i < nlabels; i++) {
- /* Special test here for what should be exact 0 (but isn't sometimes
- * due to floating-point arithmetic.
- */
- if (fabs(first/yinc_unscaled + (float)i) < 4.0e-7) { /* ugly */
- y = 0.0;
- }
- else {
- y = (first + (yinc_unscaled)*(float)i) * ppyunit;
- }
- if (y >= ymin) { /* ensure major tic mark won't be off edge */
- if (drawGrid) {
- PSsetlinewidth([gridThicknessText floatValue]);
- PSmoveto(xmin, y);
- if ([gridDotted state])
- PSsetdash(pattern2, 2, 0.0);
- else
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(ABS(xmax-xmin), 0.0);
- PSstroke();
- PSsetlinewidth([ticMarkThicknessText floatValue]);
- }
- /* Nothing at 0 if we're putting tic marks on axes: */
- if (ticLocation > 0 || y != 0.0) {
- PSmoveto(xticloc - ticmarklen*4.0, y);
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(ticmarklen*4.0, 0.0);
- PSstroke();
- if (ticLocation == 2) { /* tics on right and top */
- PSmoveto(xmax, y);
- PSsetdash(pattern0, 0, 0.0);
- PSrlineto(ticmarklen*4.0, 0.0);
- PSstroke();
- }
- handformat(y/ppyunit, ticlabel, axformat);
- xwid = [ticfont getWidthOf:ticlabel];
- PSmoveto(xticloc - xwid - MAX(10.0, 5.0*ticmarklen),
- y + 2.0 - yhgt/2.0);
- PSshow(ticlabel);
- }
- }
- if (drawMinorTics) {
- if (ticLocation > 0) { /* tics on frame */
- for (j=1; j<=9; j++) {
- ticloc = y + ((yinc_unscaled/10.0)*(float)j)*ppyunit;
- if (ticloc>ymin && ticloc<ymax) {
- PSmoveto(xticloc - ticmarklen*2.0, ticloc);
- PSrlineto(ticmarklen*2.0, 0.0);
- PSstroke();
- if (ticLocation == 2) { /* tics on right and top */
- PSmoveto(xmax, ticloc);
- PSrlineto(ticmarklen*2.0, 0.0);
- PSstroke();
- }
- }
- }
- }
- else {
- for (j=1; j<=9; j++) {
- ticloc = y + ((yinc_unscaled/10.0)*(float)j)*ppyunit;
- if (ticloc>ymin && ticloc<ymax) {
- PSmoveto(-ticmarklen, ticloc);
- PSrlineto(2.0*ticmarklen, 0.0);
- PSstroke();
- }
- }
- }
- }
- }
- }
- }
- return self;
- }
-
- - drawSelf: (const NXRect *)rects :(int)rectCount
- {
- float xmin = (float)[plotParam provideXmin];
- float xmax = (float)[plotParam provideXmax];
- float ymin = (float)[plotParam provideYmin];
- float ymax = (float)[plotParam provideYmax];
-
- [self startPlot];
-
- if ([plotParam nFiles] == 0) return self; /* no data */
-
- if (xmin==xmax || ymin==ymax) return self; /* avoid division by zero */
-
- PSgsave();
-
- PStranslate(XOFFSET, YOFFSET);
-
- if ([plotParam xaxisLog]) { /* x-axis is logarithmic */
- ppxunit = 0.9*(bounds.size.width-XOFFSET)
- /(float)log10((double)(xmax/xmin));
- xmin = (float)log10((double)xmin) * ppxunit;
- xmax = (float)log10((double)xmax) * ppxunit;
- }
- else { /* x-axis is linear */
- ppxunit = 0.9*(bounds.size.width-XOFFSET)/(xmax-xmin);
- xmin = xmin*ppxunit; /* drawing is all in pixel coordinates */
- xmax = xmax*ppxunit;
- }
- if ([plotParam yaxisLog]) { /* y-axis is logarithmic */
- ppyunit = 0.9*(bounds.size.height-YOFFSET)
- /(float)log10((double)(ymax/ymin));
- ymin = (float)log10((double)ymin) * ppyunit;
- ymax = (float)log10((double)ymax) * ppyunit;
- }
- else { /* y-axis is linear */
- ppyunit = 0.9*(bounds.size.height-YOFFSET)/(ymax-ymin);
- ymin = ymin*ppyunit;
- ymax = ymax*ppyunit;
- }
- PStranslate(-xmin, -ymin);
- // inner "frame" box
- if ([frameBoxOnOff state]) {
- PSsetlinewidth([frameBoxThicknessText floatValue]);
- PSnewpath();
- PSmoveto(xmin, ymin);
- PSlineto(xmax, ymin);
- PSlineto(xmax, ymax);
- PSlineto(xmin, ymax);
- PSclosepath();
- PSstroke();
- PSsetlinewidth(NXDrawingStatus==NX_DRAWING? 0.0: 0.4); /* reset line width */
- }
-
- if ([axesOnOff state]) {
- PSnewpath();
- PSsetlinewidth([axisThicknessText floatValue]);
- PSmoveto(0.0, ymin);
- PSlineto(0.0, ymax);
- PSstroke();
- PSmoveto(xmin, 0.0);
- PSlineto(xmax, 0.0);
- PSstroke();
- }
-
- if ([majorTicMarksOnOff state])
- [self drawTicMarks:xmin :xmax :ymin :ymax]; /* do this before clipping */
-
- /* MIN and MAX below in case xmin > xmax and/or ymin > ymax. */
- PSrectclip(MIN(xmin,xmax), MIN(ymin,ymax), ABS(xmax-xmin), ABS(ymax-ymin));
-
- [self drawLines:plotParam :[plotParam xaxisLog] :[plotParam yaxisLog]];
- [self drawSymbols:plotParam :[plotParam xaxisLog] :[plotParam yaxisLog]];
-
- [self drawErrorBars :[plotParam xaxisLog] :[plotParam yaxisLog]];
-
- PSgrestore();
- if ([legendOnOff state]) {
- [self startLegend];
- [self drawLegend:self];
- }
-
- return self;
- }
-
- - doPrinting:sender
- {
-
- id myPrintPanel = [PrintPanel new];
-
- [ [NXApp printInfo] setMarginLeft:72.0 right:72.0 top:72.0 bottom:72.0 ];
-
- if (bounds.size.height > bounds.size.width) { /* portrait mode */
- if (bounds.size.height/bounds.size.width > 9.0/6.5) {
- [ [NXApp printInfo] setScalingFactor: 9.0*72.0/bounds.size.height];
- }
- else {
- [ [NXApp printInfo] setScalingFactor: 6.5*72.0/bounds.size.width];
- }
- [ [NXApp printInfo] setOrientation:NX_PORTRAIT andAdjust:YES ];
- }
- else { /* landscape mode */
- if (bounds.size.width/bounds.size.height > 9.0/6.5) {
- [ [NXApp printInfo] setScalingFactor: 9.0*72.0/bounds.size.width];
- }
- else {
- [ [NXApp printInfo] setScalingFactor: 6.5*72.0/bounds.size.height];
- }
- [ [NXApp printInfo] setOrientation:NX_LANDSCAPE andAdjust:YES ];
- }
-
- [myPrintPanel setAccessoryView:printPanelAccessory];
-
- [self printPSCode:sender];
- return self;
- }
-
- - mouseDown:(NXEvent *)e
- /*
- * This code taken from the Mandelbrot example in /NextDeveloper (and modified).
- * We implement the mouseDown method so the user can sweep out a section of
- * the view and select that as the current window in which to view the curve(s).
- */
- {
- int looping = YES;
- int oldMask;
- NXRect bbox;
- NXPoint startPoint, currPoint;
- float xmin, xmax, ymin, ymax;
- register float t1, t2, t3, t4;
- int zooming;
- BOOL xaxislog = [plotParam xaxisLog];
- BOOL yaxislog = [plotParam yaxisLog];
-
- zooming = ZOOM;
- if (strncmp([zoomChoice title], "Zoom/Move", 9) == 0)
- zooming = NOZOOM;
- else if (strncmp([zoomChoice title], "Move legend", 11) == 0)
- zooming = MOVELEGEND;
- else if (strncmp([zoomChoice title], "Move x title", 12) == 0)
- zooming = MOVEXTITLE;
- else if (strncmp([zoomChoice title], "Move y title", 12) == 0)
- zooming = MOVEYTITLE;
- else if (strncmp([zoomChoice title], "Move main title", 15) == 0)
- zooming = MOVEMAINTITLE;
-
- if (zooming == ZOOM) { /* really zooming */
- if (xaxislog) {
- xmin = (float)log10([plotParam provideXmin]) * ppxunit;
- xmax = (float)log10([plotParam provideXmax]) * ppxunit;
- }
- else {
- xmin = [plotParam provideXmin] * ppxunit;
- xmax = [plotParam provideXmax] * ppxunit;
- }
- if (yaxislog) {
- ymin = (float)log10([plotParam provideYmin]) * ppyunit;
- ymax = (float)log10([plotParam provideYmax]) * ppyunit;
- }
- else {
- ymin = [plotParam provideYmin] * ppyunit;
- ymax = [plotParam provideYmax] * ppyunit;
- }
-
- oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
- startPoint = e->location;
- [self convertPoint:&startPoint fromView:nil];
- NXSetRect(&bbox,startPoint.x,startPoint.y,0.0,0.0);
- [self lockFocus];
- while (looping) {
- e=[NXApp getNextEvent:NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK];
- currPoint = e->location;
- [self convertPoint:&currPoint fromView:nil];
- bbox.size.width = (currPoint.x - startPoint.x);
- bbox.size.height = (currPoint.y - startPoint.y);
- /* Normalize bbox to always have positive width and height */
- if (bbox.size.width < 0) {
- bbox.size.width = -bbox.size.width;
- bbox.origin.x = startPoint.x - bbox.size.width;
- }
- if (bbox.size.height < 0) {
- bbox.size.height = -bbox.size.height;
- bbox.origin.y = startPoint.y - bbox.size.height;
- }
-
- PSnewinstance();
- if (looping = (e->type == NX_MOUSEDRAGGED)) {
- PSsetinstance(YES);
- NXSetColor([plotParam provideTextColor]);
- NXFrameRect(&bbox);
- PSsetinstance(NO);
- }
- }
- [self unlockFocus];
- [window setEventMask:oldMask];
- if ((bbox.size.width > 0) && (bbox.size.height > 0)) {
- /* At this point, bbox is in window coordinates. Convert to curve
- * coordinates based on this view's coordinates and the bounding box.
- */
-
- xmin = xmin + (bbox.origin.x - XOFFSET);
- xmax = xmin + bbox.size.width;
- ymin = ymin + (bbox.origin.y - YOFFSET);
- ymax = ymin + bbox.size.height;
-
- /* save old min/max -- must adjust if log axis */
- t1 = xmin/ppxunit;
- t2 = xmax/ppxunit;
- t3 = ymin/ppyunit;
- t4 = ymax/ppyunit;
- if (xaxislog) {
- t1 = (float) pow((double)10.0, (double)t1);
- t2 = (float) pow((double)10.0, (double)t2);
- }
- if (yaxislog) {
- t3 = (float) pow((double)10.0, (double)t3);
- t4 = (float) pow((double)10.0, (double)t4);
- }
- [plotParam stackOldMinMax:t1 :t2 :t3 :t4];
-
- if (xaxislog) {
- [plotParam resetXmin:pow((double)10.0, (double)(xmin/ppxunit))];
- [plotParam resetXmax:pow((double)10.0, (double)(xmax/ppxunit))];
- }
- else {
- [plotParam resetXmin:(double)(xmin/ppxunit)];
- [plotParam resetXmax:(double)(xmax/ppxunit)];
- }
- if (yaxislog) {
- [plotParam resetYmin:pow((double)10.0, (double)(ymin/ppyunit))];
- [plotParam resetYmax:pow((double)10.0, (double)(ymax/ppyunit))];
- }
- else {
- [plotParam resetYmin:(double)(ymin/ppyunit)];
- [plotParam resetYmax:(double)(ymax/ppyunit)];
- }
-
- /* Call [self display] to force current values of xmin/xmax/ymin/ymax
- * to take effect (otherwise xmin, etc., get incremented too many times).
- */
- [plotParam drawPlotButton:1];
- [self display];
- [plotParam drawPlotButton:0];
- }
- }
- else if (zooming >= MOVELEGEND) {
-
- oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
- startPoint = e->location;
- [self convertPoint:&startPoint fromView:nil];
- if (zooming == MOVELEGEND) {
- NXSetRect(&bbox,startPoint.x,startPoint.y,
- legendbox.size.width,legendbox.size.height);
- }
- else if (zooming == MOVEXTITLE) {
- NXSetRect(&bbox,startPoint.x,startPoint.y,
- xtitlebox.size.width,xtitlebox.size.height);
- }
- else if (zooming == MOVEYTITLE) {
- NXSetRect(&bbox,startPoint.x,startPoint.y,
- ytitlebox.size.width,ytitlebox.size.height);
- }
- else if (zooming == MOVEMAINTITLE) {
- NXSetRect(&bbox,startPoint.x,startPoint.y,
- maintitlebox.size.width,maintitlebox.size.height);
- }
- [self lockFocus];
- while (looping) {
- e=[NXApp getNextEvent:NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK];
- currPoint = e->location;
- [self convertPoint:&currPoint fromView:nil];
- bbox.origin.x = currPoint.x;
- bbox.origin.y = currPoint.y;
- PSnewinstance();
- if (looping = (e->type == NX_MOUSEDRAGGED)) {
- PSsetinstance(YES);
- NXSetColor([plotParam provideTextColor]);
- NXFrameRect(&bbox);
- PSsetinstance(NO);
- }
- }
- [self unlockFocus];
- [window setEventMask:oldMask];
- /*
- * At this point, bbox is in window coordinates.
- */
- if (zooming == MOVELEGEND) {
- legendbox.origin.x = bbox.origin.x;
- legendbox.origin.y = bbox.origin.y;
- }
- else if (zooming == MOVEXTITLE) {
- xtitlebox.origin.x = bbox.origin.x;
- xtitlebox.origin.y = bbox.origin.y;
- }
- else if (zooming == MOVEYTITLE) {
- ytitlebox.origin.x = bbox.origin.x;
- ytitlebox.origin.y = bbox.origin.y;
- }
- else if (zooming == MOVEMAINTITLE) {
- maintitlebox.origin.x = bbox.origin.x;
- maintitlebox.origin.y = bbox.origin.y;
- }
-
- /* Call [self display] to give immediate feedback */
- [plotParam drawPlotButton:1];
- [self display];
- [plotParam drawPlotButton:0];
- }
-
- return self;
- }
-
- - saveEPS:sender
- {
- id savePanel = [[SavePanel new] setRequiredFileType:"eps"];
- char *eps_fileName; // Name of the EPS file for output
-
- [savePanel setTitle:"Save EPS"]; /* make sure title is OK */
- if ([savePanel runModal]) {
- eps_fileName = (char *) calloc(strlen([savePanel filename])+1, sizeof(char));
- strcpy(eps_fileName, [savePanel filename]);
- [self savePSCode:eps_fileName];
- }
-
- return self;
- }
-
- - savePSCode:(char *)aFile
- {
- NXStream *psStream;
-
- psStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
- if (!psStream) {
- return self;
- }
- [self getBounds:&bounds];
- [self copyPSCodeInside:&bounds to:psStream];
-
- NXFlush(psStream);
- NXSaveToFile(psStream, aFile);
- NXCloseMemory(psStream, NX_FREEBUFFER);
-
- return self;
- }
-
- /*
- * Following code taken from the Graph example in NextDeveloper/Examples.
- *
- * Copies the current view into the Pasteboard as PostScript.
- */
- - copyPScode:sender
- {
- NXStream *psStream;
- id pb;
- char *data;
- int dataLen, maxDataLen;
-
- /* Open a stream on memory where we will collect the PostScript */
- psStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
- if (!psStream)
- return self;
-
- /* Tell the Pasteboard we're going to copy PostScript */
- pb = [Pasteboard new];
- [pb declareTypes:&NXPostScriptPboardType num:1 owner:self];
-
- /* writes the PostScript for the whole plot as EPS into the stream */
- [self getBounds:&bounds];
- [self copyPSCodeInside:&bounds to:psStream];
-
- /* get the buffered up PostScript out of the stream */
- NXGetMemoryBuffer(psStream, &data, &dataLen, &maxDataLen);
-
- /* put the buffer in the Pasteboard, free the stream (and the buffer) */
- [pb writeType:NXPostScriptPboardType data:data length:dataLen];
- NXCloseMemory(psStream, NX_FREEBUFFER);
- return self;
- }
-
- @end
-